#include "delegateTemplate.h"
#include <QLineEdit>
#include <iostream>
#include <QDomDocument>
#include <QSpinBox>
#include <QStandardItemModel>
#include <QModelIndex>

delegateTemplate::delegateTemplate(QDomDocument *doc, QStandardItemModel *model, quint64 fileOffset, QDataStream::ByteOrder *byteOrder, QObject *parent) : QItemDelegate(parent){
    this->doc = doc;
    this->model = model;
    this->fileOffset = fileOffset;
    this->byteOrder = byteOrder;
}

QWidget *delegateTemplate::createEditor(QWidget *parent, const QStyleOptionViewItem &/*option*/, const QModelIndex &index) const{
    QDomElement docElem;
    QDomNode n;
    QDomElement f;

    //Sprawdzenie jakiego typu jest przechowywana dana w modelu
    if(doc!=NULL){
        docElem = doc->documentElement();
        n = docElem.firstChild();
        for(int i=0; i<index.row(); ++i){
            n = n.nextSibling();
        }
        f = n.toElement();
        //std::cout<<"I've clicked field with: "<<qPrintable(f.text())<<std::endl;
    }

    //Jeśli wybrana dana jest typu tekstowego udostępniam QLineEdit
    //w przeciwnym przypadku QSpinBox dla wartości liczbowych
    if(f.text()=="char" || f.text()=="int64" || f.text()=="uint64"){
        QLineEdit *editor = new QLineEdit(parent);
        return editor;
    }else{
        QSpinBox *spinEditor = new QSpinBox(parent);
        return spinEditor;
    }
}

void delegateTemplate::setEditorData(QWidget *editor, const QModelIndex &index) const{
    //std::cout<<index.model()->data(index,Qt::EditRole).typeName()<<std::endl;
    QDomElement docElem;
    QDomNode n;
    QDomElement f;

    //Sprawdzenie jakiego typu jest przechowywana dana w modelu
    if(doc!=NULL){
        docElem = doc->documentElement();
        n = docElem.firstChild();
        for(int i=0; i<index.row(); ++i){
            n = n.nextSibling();
        }
        f = n.toElement();
    }




    //Pobranie z modelu danej o odpowiednim typie
    if(f.text()=="char" || f.text()=="int64" || f.text()=="uint64"){
        QString value = index.model()->data(index,Qt::EditRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
        lineEdit->setText(value);
    }else if(f.text()=="int8"){
        qint8 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(127);
        spinEditor->setMinimum(-128);
        spinEditor->setValue(value);
    }else if(f.text()=="uint8"){
        qint8 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(255);
        spinEditor->setMinimum(0);
        spinEditor->setValue(value);
    }else if(f.text()=="int16"){
        qint16 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(32767);
        spinEditor->setMinimum(-32768);
        spinEditor->setValue(value);
    }else if(f.text()=="uint16"){
        qint16 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(65535);
        spinEditor->setMinimum(0);
        spinEditor->setValue(value);
    }else if(f.text()=="int32"){
        qint32 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(2147483647);
        spinEditor->setMinimum(-2147483648);
        spinEditor->setValue(value);
    }else if(f.text()=="uint32"){
        qint32 value = index.model()->data(index,Qt::EditRole).toInt();
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        spinEditor->setMaximum(4294967295);
        spinEditor->setMinimum(0);
        spinEditor->setValue(value);
    }else{
        //std::cout<<"delegateTemplate: narazie obsługuję tylko char, int8, int16 i int32"<<std::endl;
    }
}

void delegateTemplate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const{
    QDomElement docElem;
    QDomNode n;
    QDomElement f;
    quint64 offset=fileOffset;
    quint32 row;
    quint32 column;
    QModelIndex modelIndex;
    QByteArray byteArray;

    //std::cout<<"offset na poczatku: "<<offset<<std::endl;

    //Sprawdzenie jakiego typu jest przechowywana dana w modelu oraz jaki ma offset w pliku
    if(doc!=NULL){
        docElem = doc->documentElement();
        n = docElem.firstChild();
        for(int i=0; i<index.row(); ++i){
            f = n.toElement();
            if(f.text()=="char"){
                for(int i=0; i<f.attribute("size").toInt(); ++i){
                    offset++;
                }
            }
            else if(f.text()=="int8" || f.text()=="uint8"){
                offset++;
            }
            else if(f.text()=="int16" || f.text()=="uint16"){
                offset+=2;
            }
            else if(f.text()=="int32" || f.text()=="uint32"){
                offset+=4;
            }
            else if(f.text()=="int64" || f.text()=="uint64"){
                offset+=8;
            }
            n = n.nextSibling();
        }
        f = n.toElement();
        //std::cout<<"I've clicked field with: "<<qPrintable(f.text())<<std::endl;
    }
    //std::cout<<"offset po zmianie: "<<offset<<std::endl;

    bool isOk = true;

    if(f.text()=="char"){
        QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
        QString value = lineEdit->text();
        model->setData(index, value, Qt::EditRole);
        byteArray = value.toAscii().toHex();
    }else if(f.text()=="int64"){
        QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
        qint64 value = lineEdit->text().toLongLong(&isOk);
        if(isOk){
            model->setData(index, value, Qt::EditRole);
            byteArray.setNum(value,16);
            if(value<0)
                byteArray.remove(0,16-2*sizeof(qint64));
            if(value>=0 && byteArray.size()<2*sizeof(qint64)){
                for(int i=byteArray.size()+1; i<=2*sizeof(qint64);++i)
                    byteArray.push_front('0');
            }
        }
    }else if(f.text()=="uint64"){
        QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
        quint64 value = lineEdit->text().toLongLong(&isOk);
        if(isOk){
            model->setData(index, value, Qt::EditRole);
            byteArray.setNum(value,16);
            if(value>=0 && byteArray.size()<2*sizeof(quint64)){
                for(int i=byteArray.size()+1; i<=2*sizeof(quint64);++i)
                    byteArray.push_front('0');
            }
        }
    }else if(f.text()=="int8"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        qint8 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        byteArray.setNum(value,16);
        if(value<0)
            byteArray.remove(0,16-2*sizeof(qint8));
        if(value>=0 && byteArray.size()<2*sizeof(qint8)){
            for(int i=byteArray.size()+1; i<=2*sizeof(qint8);++i)
                byteArray.push_front('0');
        }
    }else if(f.text()=="uint8"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        quint8 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        if(value>=0 && byteArray.size()<2*sizeof(quint8)){
            for(int i=byteArray.size()+1; i<=2*sizeof(quint8);++i)
                byteArray.push_front('0');
        }
    }else if(f.text()=="int16"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        qint16 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        byteArray.setNum(value,16);
        if(value<0)
            byteArray.remove(0,16-2*sizeof(qint16));
        if(value>=0 && byteArray.size()<2*sizeof(qint16)){
            for(int i=byteArray.size()+1; i<=2*sizeof(qint16);++i)
                byteArray.push_front('0');
        }
    }else if(f.text()=="uint16"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        qint16 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        byteArray.setNum(value,16);
        if(value>=0 && byteArray.size()<2*sizeof(quint16)){
            for(int i=byteArray.size()+1; i<=2*sizeof(quint16);++i)
                byteArray.push_front('0');
        }
    }else if(f.text()=="int32"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        qint32 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        byteArray.setNum(value,16);
        if(value<0)
            byteArray.remove(0,16-2*sizeof(qint32));
        if(value>=0 && byteArray.size()<2*sizeof(qint32)){
            for(int i=byteArray.size()+1; i<=2*sizeof(qint32);++i)
                byteArray.push_front('0');
        }
    }else if(f.text()=="uint32"){
        QSpinBox *spinEditor = static_cast<QSpinBox *>(editor);
        qint32 value = spinEditor->value();
        model->setData(index, value, Qt::EditRole);
        byteArray.setNum(value,16);
        if(value>=0 && byteArray.size()<2*sizeof(quint32)){
            for(int i=byteArray.size()+1; i<=2*sizeof(quint32);++i)
                byteArray.push_front('0');
        }
    }
    else{
        //std::cout<<"delegateTemplate: narazie obsługuję tylko char, int8, int16 i int32"<<std::endl;
    }
    //if(isOk){
        //wyznaczenie indeksu (numeru wiersza i kolumny) dla pierwszego bajtu danej
        column = (offset%16);
        row = (offset/16);
        //std::cout<<"kolumna i wiersz: "<<column<<" "<<row<<std::endl;
        modelIndex = this->model->index(row,column);

        //if(byteArray.size()%2 != 0)
        //    byteArray.push_front('0');

        //uwzględniam kolejność bajtów
        if( *byteOrder == QDataStream::LittleEndian ){
            QByteArray temp = byteArray;
            for(int i=0; i<byteArray.size(); i+=2){
                byteArray[i] = temp[(temp.size()-1)-(i+1)];
                byteArray[i+1] = temp[(temp.size()-1)-i];
            }
        }


        for(int i=0; i<byteArray.size(); i+=2){
            this->model->setData(modelIndex, QString(byteArray.at(i))+=QString(byteArray.at(i+1)),Qt::EditRole);
            std::cout<<qPrintable(QString(byteArray.at(i))+=QString(byteArray.at(i+1)))<<" "<<std::endl;
            offset++;
            column = (offset%16);
            row = (offset/16);
            modelIndex = this->model->index(row,column);
        }
    //}


}

void delegateTemplate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const{
    editor->setGeometry(option.rect);
}
